package netty.handler;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import io.netty.util.CharsetUtil;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * @author ：朱博
 * @description：自定义Handler，使用 @{ChannelInboundHandlerAdapter}
 * @date ：2021/4/12 23:06
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {


    /**
     * 根据实际数据（这里我们可以读取客户端的发送信息）
     * @param ctx 上下文对象 其中含有管道 【channel】和 通道 【pipeline】 连接地址 ...一系列连接的地址
     * @param msg 客户端发送的数据
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //打印通道的所有信息，这个消息都放在ctx上下文对象中去
        System.out.println("server ctx = " + ctx);

        /**
         * 第一种解解决方案[使用一个 eventLoop中的异步队列(每个任务的TaskQueue)来让这个任务异步执行]
         */
        //比如这里有一个非常耗时的义务，所以我们希望他异步执行，提交到义务队列中取
        Channel channel = ctx.channel();//返回一个通道
        EventLoop eventExecutors = channel.eventLoop();//放反向获取到当前这个执行线程的任务NioEventLoopGroup
        eventExecutors.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ctx.writeAndFlush(Unpooled
                        .copiedBuffer("hellom,客户端，我是耗时业务的结果1",CharsetUtil.UTF_8));
            }
        });//让这个eventLoop执行一个我们自定义的任务，并且提交到它的任务队列中去
        /**
         * 这里是一个定时任务
         */
        eventExecutors.schedule(() -> {
            try {
                Thread.sleep(5*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ctx.writeAndFlush(Unpooled
                    .copiedBuffer("hellom,客户端，我是一个服务端的延时任务",CharsetUtil.UTF_8));
        },15, TimeUnit.SECONDS);

        /*
         * 由于Nio的原理是数据是在 Buffer 里面的 ，所以把msg转换为 buffer 类型效率比较高
         */
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("server address : "+
                ctx.channel().remoteAddress()+
                "client send message :" +
                byteBuf.toString(CharsetUtil.UTF_8));

    }

    /**
     * 读取数据以后的方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("我是馍馍，我在学习Netty",CharsetUtil.UTF_8));
    }

    /**
     * 处理异常的方法
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();//如果发送异常，那么就关闭通道
    }
}
